﻿//-----------------------------------------------------------------------
// <copyright file="Cell.cs" company="cx studio">
//      2013-11-16
//     Copyright (c) cx studio. All rights reserved.
// </copyright>
// <author>Xi Chen</author>
//-----------------------------------------------------------------------
namespace CentralFoveaLib.Brain
{
    using CentralFoveaLib.ColorProcess;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

    /// <summary>
    /// 最近我观察蚂蚁以及查找关于细菌相关的行为后，我觉得思维是由单个细胞完成的，就像蚂蚁一样。每个蚂蚁就是一个小事件，
    /// 因为这些小事件的完成，最后形成一些我们看上去是智能的行为,蚁群强调的是蚂蚁的聚集行为。但是，我觉得这些智能主要靠的是单个蚂蚁的运作。
    /// 就像蚂蚁找到食物饭后发送信号，但是它不是这么简单的一个操作，它会观察食物，给同伴沟通。所以单个蚂蚁不是只简单的移动，而是他作为一个个体
    /// 他就已经有丰富的行为，而这些丰富的行为才造就了我们可以看到的蚂蚁群搬东西，蚂蚁战胜对手.
    /// 所以我要用NCell去模拟单个蚂蚁的运作。我们的神经系统就像蚂蚁一样，
    /// 他们有着一些基本的行为。可能不只是简单的的到相应，然后计算权值，最后输出。
    /// 他们有更丰富的行为,而且有分化
    /// http://news.sciencenet.cn/htmlpaper/2011112213304039020682.shtm
    /// 分化就以为着它可以不需要更多的神经元来完成他们的工作
    /// 细菌也是一种群体生物，他们有感受器，他们通过统计周围的蛋白质分子来确定自己现在该做什么
    /// 如果他们统计自己周围同类型的细菌达到一定的密度，他们就会一起响应，如一起致病或者发光。
    /// 所以他们完成的是一个统计。
    /// 如果一个细菌有两个感受器，那么他可以统计两种类型的信号
    /// 例如一个是自己同类的， 一个是所有细菌类型的共同语言。
    /// 如果再多一个种类的感受器，它就可以感受到其它类型的细菌信号。
    /// 那么每一个细菌内部做了什么了？他们根据接收的信号来向外发送信号
    /// 他们根据基因里面固化好的条件判断信号的回复。
    /// 那么细胞进化的，就是进化他的信号处理。
    /// 那么DNA就标识了当前的细胞应该做什么。
    /// 他们为什么这样做？这样做的作用，就是为了让整个种群存在下去。
    /// 我们给这些细胞群，让他们根据输入的图片，然后他进行分类。如果错误他们将会被淘汰。
    /// 同一个生物个体他们的DNA完全一样。
    /// DNA
    /// 每8位表示一个片段1表示下一个8位还有数据
    /// 00000000
    /// 这些片段用来标记，[接收器1]->[输出1],[接收器2][接收器3]->[输出2]
    /// 细胞的功能 有不发送信号,发送信号
    /// 需要知道自己是哪种类型，发出的信号
    /// 主要的思想是，每一个小的细胞就是一个小的有向网络,人类的比较发达，所以我们的一个神经细胞，就可以链接达到一万。
    /// 蚂蚁，它可以影响到周围数十个到百个。
    /// 细菌，它可以影响到周围的数十个或者百个。
    /// 而我们的计算机网络，也是分区的。虽然在地理机构上他们没有分区，但是如果按网站来分的话，那些人用baidu?那些人用Google?
    /// 那些人上163,那些人看微博，那些人上微信，那些人上csdn,cnblogs?
    /// 我们在地域上不一样，但是我们最终可能去上自己最爱去的那几个。
    /// 如果一个生物或者购物信息出现在csdn上，那么可能看的人就没那么多，但是如果一段有趣的编程文章，那么就可以吸引很多人来看。
    /// 如果163上出现一些科技信息，我会在科技频道上看。但是如果是一篇编程文章，放在最显眼的地方，也许我也不会注意。
    /// 也许进化是为了整个种群延续下去，也许我们自己也没想好为什么要哺育下一代。当然如果我们不那么做，我们在怎么聪明，很快种族就灭亡。所以这是进化的结果
    /// 那么我们的变异发生在那里了？我们整个个体突然发生变异不太可能，它发生在细胞级别，也就是因为它们的变异，然后出现了多样性。
    /// 所以我们需要一个胚胎这样的原始的类型，然后在上面发生进化。进化让我们有了新的分类。我们总是把相同功能的细胞放在一起。
    /// 
    /// 只需要定义输入端的接收器，输出端的接收器
    /// 其它类型的Cell会自动根据，在同一层的相同类型的Cell进行聚集，也就是说，如果同一层的相同Cell不够多，那么它就不工作,他们会移动到自己周围同类型多的地方。
    /// 如果同类不多，那么他们优先向与自己输入类似的地方聚集,改变自己的层次
    /// 现在我有一个困惑，就是我不知道每个细胞是只考虑一个问题，还是会同时考虑很多问题？还是一群细胞只负责一个问题？还是一群细胞负责多个但属于同一个类型的问题？
    /// </summary>
    public class NCell
    {
        #region 变量定义
        /// <summary>
        /// 级别
        /// </summary>
        //public int Level { get; set; }


        /// <summary>
        /// 类型
        /// </summary>
        public int Type { get; set; }

        public String DNA { get; set; }

        public List<DNASegment> DNASegments { get; set; }

        public IList<NCell> Input { get; set; }
        public IDictionary<int, B> InputType { get; set; }
        public IList<NCell> Output { get; set; }

        public IList<NCell> Same { get; set; }

        /// <summary>
        /// 用来存储它的值
        /// </summary>
        private IDictionary<int, int> values { get; set; }

        public int OutputType { get; set; }
        #endregion

        public void Init()
        {
            //从DNA中得到自己的发送信号和接受信号是什么
            //先是Level
            //[类型1的输入:数量]|[输出的类型A];
            //[类型1的输入:数量]|[类型2的输入:数量]|[输出类型B]
            //解螺旋：
            // D_1#10:9^100|12:1001|132;
            SetDefault();

            String tempDNA = DNA;
            Type = int.Parse(tempDNA.Split('#')[0].Split('_')[1]);
            String[] segments = tempDNA.Split('#')[1].Split('|');
            for (int i = 0; i < segments.Length - 1; i++)
            {
                var item = segments[i];
                String[] blocks = item.Split(':');
                String[] b = blocks[1].Split('^');
                InputType[int.Parse(blocks[0])] = new B() { L = int.Parse(b[0]), V = int.Parse(b[1]) };

            }
            int outputBlock = int.Parse(segments[segments.Length - 1]);

            OutputType = outputBlock;
        }

        /// <summary>
        /// 他们的运作方式是从底层一层层的向外发送
        /// </summary>
        public void Process()
        {
            SetDefault();
            DNASegment seg = Contain();
            if (seg != null)
            {
                for (int i = 0; i < Output.Count; i++)
                {
                    var item = Output[i];
                    item.SetInvoke(seg.OutputType, 1);
                }
            }
            this.ClearValue();
        }

        private DNASegment Contain()
        {
            foreach (var item in DNASegments)
            {

                if (IsSame(item))
                {
                    bool pass = true;
                    foreach (var v in values)
                    {
                        //当前片段的值与与每一个输入比较，如果输入的值比阀值要高，那么细胞就响应
                        if (item.InputType.ContainsKey(v.Key) && item.InputType[v.Key] < v.Value)
                        {

                        }
                        else
                        {
                            pass = false;
                        }
                    }
                    return pass ? item : null;
                }
            }
            return null;
        }


        private bool IsSame(DNASegment seg)
        {
            if (seg.InputType.Count == values.Count)
            {
                return true;
            }
            return false;
        }

        public void SetInvoke(int key, int value)
        {
            this.SetDefault();
            if (this.values.ContainsKey(key))
            {
                this.values[key] += value;
            }
            else
            {
                this.values[key] = value;
            }

        }
        private void SetDefault()
        {
            if (DNASegments == null)
            {
                DNASegments = new List<DNASegment>();
            }
            if (Input == null) Input = new List<NCell>();
            if (Output == null) Output = new List<NCell>();
            if (values == null) { this.values = new Dictionary<int, int>(); }
            if (InputType == null) InputType = new Dictionary<int, B>();
        }
        private void ClearValue()
        {
            values.Clear();
        }

        public void CloneSelfToCells(List<NCell> cells)
        {
            for (int i = 0; i < cells.Count; i++)
            {
                var eachCell = cells[i];
                // eachCell.
            }
        }

    }

    public class DNASegment
    {
        public DNASegment() { InputType = new Dictionary<int, int>(); }
        public IDictionary<int, int> InputType { get; set; }
        public int OutputType { get; set; }
    }

    public class B
    {
        public int L { get; set; }
        public int V { get; set; }
    }

    public class TestCells
    {
        public IList<String> RandomDNA(IDictionary<int, int> outputTypes)
        {
            //根据输入的Cell值，生成输出的Cell
            //他可以生成多个连接
            // D_1#10:100|12:1001-132;
            IDictionary<String, String> newTypeCell = new Dictionary<String, String>();
            for (int i = 0; i < 1000; i++)
            {
                String dna = BuildDNA(i, outputTypes);
                newTypeCell[dna] = dna;
            }
            return newTypeCell.Keys.ToList<String>();
        }

        private static IDictionary<int, B> dict = new Dictionary<int, B>();
        //private static 
        private static string BuildDNA(int i, IDictionary<int, int> outputTypes)
        {
            Random random = new Random(new Guid().GetHashCode());
            int minInputType = 1;//输入的类型
            int maxInputType = 1024 * 4;
            //int minTypeCount = 1;//每个细胞最多包含的类型
            //int maxTypeCount = 128;
            int minOutputType = 1;
            int maxOutputType = maxInputType;

            int minL = 1;
            int maxL = 9;

            String dna = String.Format("D_{0}#", i + 1);
            // var nCell = new NCell();
            //nCell.
            int typeCount = random.Next(1, outputTypes.Count);

            for (int j = 0; j < typeCount; j++)
            {
                int inputType = random.Next(minInputType, maxInputType);
                while (!outputTypes.ContainsKey(inputType))
                {
                    inputType = random.Next(minInputType, maxInputType);
                }
                int l = random.Next(minL, maxL);
                int v = random.Next(l * 2);
                dict[inputType] = new B() {L=l,V =v };
            }
            StringBuilder builder = new StringBuilder();
            foreach (var item in dict)
            {
                builder.Append(String.Format("{0}:{1}^{2}|", item.Key, item.Value.L,item.Value.V));
            }
            dna += builder.ToString().TrimEnd('|');

            int outputType = random.Next(minOutputType, maxOutputType);
            dna += String.Format("|" + outputType);
            return dna;
        }

        public NCell[][] BuildInputCell(CCell[][] cell)
        {
            NCell[][] list = new NCell[cell.Length][];
            //入参事Cell的类型,可以将输入类型标记为0
            //每一个Cell将对应一个NCell,NCell自身的Value是0
            for (int i = 0; i < cell.Length; i++)
            {
                var row = cell[i];
                list[i] = new NCell[row.Length];
                for (int j = 0; j < row.Length; j++)
                {
                    var col = row[j];
                    var nCell = new NCell() { Type = 0 };
                    int gray = Convert.ToInt32(col.Gray);
                    // D_1#0:1|**;
                    nCell.DNA = "D_0#0:1^0|" + gray;
                    nCell.Init();
                    nCell.SetInvoke(0, gray);
                    // list.Add(nCell);
                    list[i][j] = nCell;
                }
            }
            return list;
        }

        public List<NCell> BuildNextCell(IList<String> DNAS)
        {
            List<NCell> newCell = new List<NCell>();
            for (int i = 0; i < DNAS.Count; i++)
            {
                var nCell = new NCell();
                nCell.DNA = DNAS[i];
                nCell.Init();
                newCell.Add(nCell);
            }

            return newCell;
        }

        public List<NCell> BuildCellTemplateByCell(NCell[][] lastNCells)
        {
            IDictionary<int, int> outputTypes = new Dictionary<int, int>();
            for (int i = 0; i < lastNCells.Length; i++)
            {

                var row = lastNCells[i];
                for (int j = 0; j < row.Length; j++)
                {
                    var item = lastNCells[i][j];
                    int outputType = item.OutputType;
                    outputTypes[outputType] = outputType;
                }

            }

            List<NCell> nCells = GetRandomTemplate(outputTypes);
            return nCells;
        }

        private List<NCell> GetRandomTemplate(IDictionary<int, int> outputTypes)
        {
            List<NCell> nCells = new List<NCell>();
            if (outputTypes.Count == 0)
            {
                return nCells;
            }
            var nCellTemplate = BuildNextCell(RandomDNA(outputTypes));
            Console.WriteLine("nCellTemplate:" + nCellTemplate.Count);
            foreach (var item in nCellTemplate)
            {

                var segList = item.InputType;
                int isContain = 0;
                foreach (var seg in segList)
                {
                    if (outputTypes.ContainsKey(seg.Key))
                    {
                        isContain++;
                    }
                }
                if (isContain == segList.Count)
                {

                    nCells.Add(item);
                }
            }
            if (nCells.Count == 0) nCells = GetRandomTemplate(outputTypes);
            return nCells;
        }

    }
}
